import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BLE } from '@ionic-native/ble';
import { Device } from '@ionic-native/device';
import { DialogProvider } from '../../providers/dialog/dialog';
import { DeviceInfoDataService } from '../../providers/service/deviceInfo-data.service';
import { LoadingController, Loading, IonicPage, NavController, NavParams, ModalController, ViewController } from 'ionic-angular';
import { EventProvider } from '../../providers/event/event' ;
import { CCPeriodDataService } from '../service/cCPeriod-data.service';
/*
  Generated class for the UserInfoProvider provider.

  See https://angular.io/guide/dependency-injection for more info on providers
  and Angular DI.
*/
@Injectable()
export class BleProvider {

  private head = {
    bHeadMark: 'LKB', //3字节 要经过ASCII码转换
    bVer: 1, //1字节
    bLength: null, //2字节
    bCmdld: null, //2字节
    bSeq: 0, //2字节
    bCks: null //2字节
  }

  private discharge = {
    userid: String, //4字节
    mins: String //4字节
  }

  private charge = {
    up1: String, //2字节
    up2: String //2字节
  }

  private time = {
    year: String, //1字节
    month: String, //1字节
    day: String, //1字节
    hour: String, //1字节
    min: String, //1字节
    sec: String //1字节
  }

  private equipmentNum = {
    device_id: String, //4字节
    reserver_code: String, //1字节
    index_code: String //1字节
  }

  //选中的蓝牙信息
  public info = '';
  public infoOld = '';
  //选中的蓝牙下标
  public device;

  //扫描出的蓝牙设备
  public devices = new Array();

  public notifyInfo = new Array();

  public device_state = 'off';

  public power_unit_id;

  constructor(
    public http: HttpClient,
    public ble: BLE,
    public dialog: DialogProvider,
    public cordova_plugin_device: Device,
    public deviceInfo: DeviceInfoDataService,
    public loadingCtrl: LoadingController,
    public event: EventProvider,
    public cCPeriod: CCPeriodDataService
  ) {
    console.log('Hello BleProvider Provider');
  }


  /**
   * 生成头包
   * @param bHeadMark 
   * @param bVer 
   * @param bLength 
   * @param bCmdld 
   * @param bSeq 
   * @param bCks 
   */
  assembleHeadBuffer(bHeadMark: String, bVer: number, bLength: number, bCmdld: String, bSeq: number, bCks: number) {
    let head = {
      bHeadMark: null,
      bVer: null,
      bLength: null,
      bCmdld: null,
      bSeq: null,
      bCks: null
    }

    let headBuffer: String;

    head.bHeadMark = this.stringToHex(bHeadMark);
    head.bVer = this.supplementZer0((bVer).toString(16), 1);
    head.bLength = this.supplementZer0((bLength).toString(16), 2);
    head.bCmdld = bCmdld;
    head.bSeq = this.supplementZer0((bSeq).toString(16), 2);
    head.bCks = this.supplementZer0((bCks).toString(16), 2);
    let buffer = head.bHeadMark + head.bVer + head.bLength + head.bCmdld + head.bSeq;
    head.bCks = this.checksum(buffer, 10);
    headBuffer = head.bHeadMark + head.bVer + head.bLength + head.bCmdld + head.bSeq + head.bCks;

    return headBuffer;

  }

  /**
   * 用0补充位数
   * @param str 
   * @param num 
   */
  supplementZer0(str: String, num: number): any {
    var pos = 0;
    num *= 2;
    var len = str.length;

    if (len !== num) {
      for (let i = 0; i < num - len; i++) {
        str = '0' + str;
      }
    }


    return str;
  }

  /**
   * 字符串转ASCII码
   * @param str 
   */
  stringToHex(str) {
    var val = "";
    for (var i = 0; i < str.length; i++) {
      if (val == "")
        val = str.charCodeAt(i).toString(16);
      else
        val += str.charCodeAt(i).toString(16);
    }
    return val;
  }

  ling(data) {
    let a = '';
    for (let d of data) {
      a += d;
    }
    return a;
  }

  /** 
   * 选择蓝牙设备
   */
  selected(id, device) {
    this.info = id;
    this.device = device;
  }

  /**
   * 蓝牙扫描
   */
  async scan(num) {
    let loading;
    if (num === 1) {
      loading = this.loadingCtrl.create({
        content: '蓝牙搜索中...'//数据加载中显示
      });
      loading.present();
    }

    if (this.cordova_plugin_device.platform === 'Android') {
      await this.ble.enable();
      this.devices.splice(0);
      this.ble.scan([], 10).subscribe(device => {
        this.devices.push(device);    
        this.androidAdvertising(device);
      });
    }
    if (this.cordova_plugin_device.platform === 'iOS') {
      // await this.ble.enable();
      this.devices.splice(0);
      this.ble.scan([], 10).subscribe(device => {
        this.devices.push(device);
        this.event.sendEvents(this.event.EVENT_BLEdevice,{device:device});
        this.iosAdvertising(device);
      });
    }
    if (num === 1) {
      setTimeout( (res) => {
        loading.dismiss();
      },1000);
     
    }
  }

  androidAdvertising(device) {
    var adData = (new Uint8Array(device.advertising)).toString().split(',');
    let a = '';
    for (let b of adData) {
      a = a + this.supplementZer0(parseInt(b).toString(16), 1);
    }
    let c = a.slice(10, 62);
    device.device_id = c.slice(0, 8);
    device.charger_times = c.slice(8, 16);
    device.work_minutes = c.slice(16, 24);
    device.device_status = c.slice(24, 32);
    device.uint_price1 = c.slice(32, 36);
    device.continuechargetime = parseInt(c.slice(36, 38), 16);
    device.group_id = c.slice(38, 40);
    device.device_index = c.slice(40, 42);
    device.rc_total = c.slice(42, 44);
    device.chargingtimerequest = parseInt(c.slice(44, 48), 16);
    device.chargingtime = parseInt(c.slice(48, 52), 16);
    device.mac = a[80].toUpperCase() + a[81].toUpperCase() + ':' + a[82].toUpperCase() + a[83].toUpperCase() + ':' + a[84].toUpperCase() + a[85].toUpperCase() + ':' + a[86].toUpperCase() + a[87].toUpperCase() + ':' + a[88].toUpperCase() + a[89].toUpperCase() + ':' + a[90].toUpperCase() + a[91].toUpperCase();
    device.cid = a[92] + a[93] + a[94] + a[95];
    device.abnormal_user = a[96] + a[97] + a[98] + a[99] + a[100] + a[101] + a[102] + a[103];
    // a.slice(80, 92);
    let bit = '';
    for (let i = 0; i < device.device_status.length; i++) {
      bit += this.supplementZer0(parseInt(device.device_status[i] + device.device_status[i + 1], 16).toString(2), 4);
      i++;
    }
    device.work_status = bit[0] //设备状态 0正常 1故障
    device.use_status = bit[31];; //使用状态 0空闲 1充电中
    device.discharge_status = bit[30]; //放电状态 0-正常放电，1--异常放电
    this.event.sendEvents(this.event.EVENT_BLEdevice,{device:device});
    // this.dialog.showAlert(JSON.stringify(device.name), '使用状态=' + JSON.stringify(device.use_status) + ',设备状态=' + JSON.stringify(device.work_status) + ',放电状态=' + JSON.stringify(device.discharge_status) + ',异常用户=' + JSON.stringify(device.abnormal_user)+ '####' +a);
  }

  iosAdvertising(device) {
    var adData = (new Uint8Array(device.advertising.kCBAdvDataManufacturerData)).toString().split(',');
    let a = '';
    for (let b of adData) {
      a = a + this.supplementZer0(parseInt(b).toString(16), 1);
    }
    let c = a.slice(0, 52);
    device.device_id = c.slice(0, 8);
    device.charger_times = c.slice(8, 16);
    device.work_minutes = c.slice(16, 24);
    device.device_status = c.slice(24, 32);
    device.uint_price1 = c.slice(32, 36);
    device.continuechargetime = parseInt(c.slice(36, 38), 16);
    device.group_id = c.slice(38, 40);
    device.device_index = c.slice(40, 42);
    device.rc_total = c.slice(42, 44);
    device.chargingtimerequest = parseInt(c.slice(44, 48), 16);
    device.chargingtime = parseInt(c.slice(48, 52), 16);
    device.mac = a[52].toUpperCase() + a[53].toUpperCase() + ':' + a[54].toUpperCase() + a[55].toUpperCase() + ':' + a[56].toUpperCase() + a[57].toUpperCase() + ':' + a[58].toUpperCase() + a[59].toUpperCase() + ':' + a[60].toUpperCase() + a[61].toUpperCase() + ':' + a[62].toUpperCase() + a[63].toUpperCase();
    device.cid = a[64] + a[65] + a[66] + a[67];
    device.abnormal_user = a[68] + a[69] + a[70] + a[71] + a[72] + a[73] + a[74] + a[75];
    // device.id = device.mac;
    let bit = '';
    for (let i = 0; i < device.device_status.length; i++) {
      bit += this.supplementZer0(parseInt(device.device_status[i] + device.device_status[i + 1], 16).toString(2), 4);
      i++;
    }
    device.work_status = bit[0]; //设备状态 0正常 1故障
    device.use_status = bit[31]; //使用状态 0空闲 1充电中
    device.discharge_status = bit[30]; //设备状态 0-正常放电，1--异常放电

    this.event.sendEvents(this.event.EVENT_BLEdevice,{device:device});
    // this.dialog.showAlert(JSON.stringify(device.name), '使用状态=' + JSON.stringify(device.use_status) + ',设备状态=' + JSON.stringify(device.work_status) + ',放电状态=' + JSON.stringify(device.discharge_status) + ',异常用户=' + JSON.stringify(device.abnormal_user));
  }


  /**
   * 蓝牙写入 0110
   * @param buf 
   */
  async write0110() {
    let head = {
      bHeadMark: 'LKB', //3字节 要经过ASCII码转换
      bVer: 1, //1字节
      bLength: 18, //2字节
      bCmdld: '0110', //2字节
      bSeq: 0, //2字节
      bCks: 1111 //2字节
    }

    let headBuffer = this.assembleHeadBuffer(head.bHeadMark, head.bVer, head.bLength, head.bCmdld, head.bSeq, head.bCks);
    let year = this.supplementZer0(parseInt(new Date().getFullYear().toString().slice(2, 4)).toString(16), 1) + this.supplementZer0((new Date().getMonth() + 1).toString(16), 1) + this.supplementZer0((new Date().getDate()).toString(16), 1) + this.supplementZer0((new Date().getHours()).toString(16), 1) + this.supplementZer0((new Date().getMinutes().toString(16)), 1) + this.supplementZer0((new Date().getSeconds().toString(16)), 1);
    headBuffer = headBuffer + year;
    var a1 = new Uint8Array(18);
    // this.dialog.showAlert('0110提示', headBuffer);
    let j = 0;
    for (let i = 0; i < headBuffer.length - 1; i++) {
      a1[i] = parseInt(headBuffer[j] + headBuffer[j + 1], 16);
      j = j + 2;
    }
    await this.ble.write(this.info, 'FEC0', 'FEC1', a1.buffer);
  }

  /**
   * 蓝牙写入 0020
   * @param buf 
   */
  async write0020(headBuffer: String, dataBuffer: String) {
    // this.dialog.showAlert('0020提示', buf);
    // let year = this.supplementZer0(parseInt(new Date().getFullYear().toString().slice(2, 4)).toString(16), 1) + this.supplementZer0((new Date().getMonth() + 1).toString(16), 1) + this.supplementZer0((new Date().getDate()).toString(16), 1) + this.supplementZer0((new Date().getHours()).toString(16), 1) + this.supplementZer0((new Date().getMinutes().toString(16)), 1) + this.supplementZer0((new Date().getSeconds().toString(16)), 1);
    // dataBuffer = year + dataBuffer;
    await this.write0020split(headBuffer, 12);
    await this.write0020split(dataBuffer, 12);
  }

  async write0020split(buf: String, num: number) {
    var a1 = new Uint8Array(num);
    // this.dialog.showAlert('0020提示', buf);
    let j = 0;
    for (let i = 0; i < buf.length - 1; i++) {
      a1[i] = parseInt(buf[j] + buf[j + 1], 16);
      j = j + 2;
    }
    // await this.notify()
    await this.ble.write(this.info, 'FEC0', 'FEC1', a1.buffer);
  }

  /**
   * 蓝牙写入 0300
   * @param buf 
   */
  async write0030() {
    let head = {
      bHeadMark: 'LKB', //3字节 要经过ASCII码转换
      bVer: 1, //1字节
      bLength: 12, //2字节
      bCmdld: '0300', //2字节
      bSeq: 0, //2字节
      bCks: 1111 //2字节
    }

    let headBuffer = this.assembleHeadBuffer(head.bHeadMark, head.bVer, head.bLength, head.bCmdld, head.bSeq, head.bCks);
    var a1 = new Uint8Array(12);
    // this.dialog.showAlert('0300提示', headBuffer);
    let j = 0;
    for (let i = 0; i < headBuffer.length - 1; i++) {
      a1[i] = parseInt(headBuffer[j] + headBuffer[j + 1], 16);
      j = j + 2;
    }
    await this.ble.write(this.info, 'FEC0', 'FEC1', a1.buffer);
  }

    /**
   * 蓝牙写入 0150
   * @param buf 
   */
  async write0150() {
    let head = {
      bHeadMark: 'LKB', //3字节 要经过ASCII码转换
      bVer: 1, //1字节
      bLength: 13, //2字节
      bCmdld: '0150', //2字节
      bSeq: 0, //2字节
      bCks: 1111 //2字节
    }

    let headBuffer = this.assembleHeadBuffer(head.bHeadMark, head.bVer, head.bLength, head.bCmdld, head.bSeq, head.bCks);
    var a1 = new Uint8Array(13);
    const time = await this.cCPeriod.find((a) => a.key !== '');
    // this.dialog.showAlert('0150提示', headBuffer);
    a1 = a1 + this.supplementZer0(time[0].abnormal_last_time.toString(16), 1);
    let j = 0;
    for (let i = 0; i < headBuffer.length - 1; i++) {
      a1[i] = parseInt(headBuffer[j] + headBuffer[j + 1], 16);
      j = j + 2;
    }
    await this.ble.write(this.info, 'FEC0', 'FEC1', a1.buffer);
  }

	/**
	 * 蓝牙写入 APP校验
	 * @param buf 
	 */
  async writeAPP(userid) {

    this.ble.startNotification(this.info, 'FFF0', 'FFF2').subscribe(buffer => {
      // let a = '';
      // a = '';
      // var adData = (new Uint8Array(buffer)).toString().split(',');
      // for (let b of adData) {
      //   a = a + this.supplementZer0(parseInt(b).toString(16), 1);
      // }

      // this.dialog.showAlert('监听提示1', String.fromCharCode.apply(null, new Uint8Array(buffer)));
      if (String.fromCharCode.apply(null, new Uint8Array(buffer)) === 'KEY:OK') {
        // APP校验通过
        setTimeout((res) => {
          this.notify();
          this.write0030();
          this.write0150();
        },200)
        // var a1 = new Uint8Array(10);
        // let hr = this.stringToHex('ERASE');
        // let j = 0;
        // for (let i = 0; i < hr.length - 1; i++) {
        //   a1[i] = parseInt(hr[j] + hr[j + 1], 16);
        //   j = j + 2;
        // }
        // this.ble.write(this.info, 'FFF0', 'FFF1', a1.buffer);

      } else {
        this.dialog.showAlert('APP校验失败', String.fromCharCode.apply(null, new Uint8Array(buffer)));
      }
    });


    let head = {
      identify: 'KEY:', //3字节 要经过ASCII码转换
      userid: userid, //1字节
      timestamp: new Date().getTime(), //2字节
      randnum: parseInt('5', 10), //2字节      (Math.floor(Math.random()*(100-1+1)+1)).toString()
      checknum: 1111 //2字节
    }

    let buffer = {
      identify: null,
      userid: null,
      timestamp: null,
      randnum: null,
      checknum: null,
    }

    buffer.identify = this.stringToHex(head.identify);
    buffer.userid = this.supplementZer0((head.userid).toString(), 4);
    buffer.timestamp = this.supplementZer0((head.timestamp).toString(16), 8);
    buffer.randnum = this.supplementZer0((head.randnum).toString(16), 2);
    let str = buffer.identify + buffer.userid + buffer.timestamp + buffer.randnum;
    buffer.checknum = this.checksum(str, 18);

    let headBuffer = buffer.identify + buffer.userid + buffer.timestamp + buffer.randnum + buffer.checknum;
    // let headBuffer = '4b45593affffffff000001635c68740a8d4af863'
    var a1 = new Uint8Array(20);
    // this.dialog.showAlert('0300提示', headBuffer);
    let j = 0;
    for (let i = 0; i < headBuffer.length - 1; i++) {
      a1[i] = parseInt(headBuffer[j] + headBuffer[j + 1], 16);
      j = j + 2;
    }
    await this.ble.write(this.info, 'FFF0', 'FFF1', a1.buffer);
  }

  /**
   * 蓝牙连接
   */
  async connect(userid) {
    let loading = this.loadingCtrl.create({
      content: '蓝牙连接中...'//数据加载中显示
    });
    loading.present();
    this.disconect();
    // this.dialog.showAlert('device', JSON.stringify(userid));
    if (this.device) {
      // this.dialog.showAlert('discharge_status', JSON.stringify(this.device.discharge_status === 1));
      if (this.device.discharge_status === '1') {
        // this.dialog.showAlert('discharge_status', JSON.stringify(this.device.abnormal_user));
        if (parseInt(this.device.abnormal_user) === parseInt(userid)) {
          await this.ble.connect(this.info).subscribe(res => {
            this.infoOld = this.info;
            setTimeout((res) => {
              this.writeAPP(userid);
            },200)
            // this.notify();
            // this.write0030()
            this.device_state = 'on';
            loading.dismiss();
            // this.dialog.showAlert('已经开始续充', '');
            this.event.sendEvents(this.event.EVENT_BLEconnect, {code: 1});
          },
            res => {
              this.device_state = 'off';
              // this.dialog.showAlert('蓝牙连接失败请重新操作', '');
              this.event.sendEvents(this.event.EVENT_BLEconnect, {code: 2});
              loading.dismiss();
            });
            return 1;
        }
      }
    } 
    
      await this.ble.connect(this.info).subscribe(res => {
        this.infoOld = this.info;
        setTimeout((res) => {
          this.writeAPP(userid);
        },200)
        // this.notify();
        // this.write0030()
        this.device_state = 'on';
        loading.dismiss();
        // this2.dialog.showToast('middle', '蓝牙连接成功，请选择充电时间');
        this.event.sendEvents(this.event.EVENT_BLEconnect, {code: 3});

      },
        res => {
          this.device_state = 'off';
          // this.dialog.showAlert('蓝牙连接失败请重新操作', '');
          this.event.sendEvents(this.event.EVENT_BLEconnect, {code: 4});
          loading.dismiss();
        });
        return 3;
  }

  /**
   * 蓝牙读取
   */
  read() {
    // 设备
    this.ble.read(this.info, 'FEC0', 'FEC2').then(buffer => {
      this.dialog.showAlert('提示', String.fromCharCode.apply(null, new Uint8Array(buffer)));
    });
  }

  /**
   * 蓝牙监听
   */
  async notify() {
    let a = '';

    // this.dialog.showAlert('设备监听提示', JSON.stringify(oldDeviceInfo.length));
    this.ble.startNotification(this.info, 'FEC0', 'FEC2').subscribe(buffer => {
      a = '';
      var adData = (new Uint8Array(buffer)).toString().split(',');
      for (let b of adData) {
        a = a + this.supplementZer0(parseInt(b).toString(16), 1);
      }
      if (a[0].toLowerCase() === '4' && a[1].toLowerCase() === 'c' && a[2].toLowerCase() === '4' && a[3].toLowerCase() === 'b' && a[4].toLowerCase() === '4' && a[5].toLowerCase() === '2') {
        // this.dialog.showAlert('监听提示', a);
        if (a[12] === '0' && a[13] === '2' && a[14] === '0' && a[15] === '1') {
          if (a[a.length - 1] === '0' && a[a.length - 2] === '0') {
            this.dialog.showAlert('放电成功', '');
            // this.disconect();
          } else {
            this.dialog.showAlert('放电失败', a);
            // this.disconect();
          }
        }
      } else {
        let info = {
          rc_index: a[0] + a[1],
          chargingtimerequest: a[2] + a[3] + a[4] + a[5],
          chargingtime: a[6] + a[7] + a[8] + a[9],
          userid: a[10] + a[11] + a[12] + a[13] + a[14] + a[15] + a[16] + a[17],
          deviceid: a[18] + a[19] + a[20] + a[21] + a[22] + a[23] + a[24] + a[25],
          datetime: a[26] + a[27] + a[28] + a[29] + a[30] + a[31] + a[32] + a[33] + a[34] + a[35] + a[36] + a[37],
          upload: 0, // 上传1 未上传0
          power_unit_id: this.power_unit_id,
          abnormal: a[38] + a[39],
          notifyInfo: a,
        }
        if (info.chargingtime.toLowerCase() === 'ffff') {
          info.chargingtime = '0';
        }
        if (info.chargingtimerequest.toLowerCase() === 'ffff') {
          info.chargingtimerequest = '0';
        }
        info.chargingtime = parseInt(info.chargingtime,16).toString();
        info.chargingtimerequest = parseInt(info.chargingtimerequest,16).toString();
        this.deviceInfo.find((data) => data.notifyInfo === info.notifyInfo).then((oldDeviceInfo) => {
          if (oldDeviceInfo.length > 0) {
            // this.dialog.showAlert('设备监听提示1', '已存在');
          } else {
            this.deviceInfo.save(info);
            // this.dialog.showAlert('设备监听提示2', JSON.stringify(info));
          }
        });
      }
    });
  }

  /**
   * 蓝牙停止监听
   */
  async stopnotify() {
    this.ble.stopNotification(this.info, 'FEC0', 'FEC2').then(buffer => {
      // this.dialog.showAlert('提示', String.fromCharCode.apply(null, new Uint8Array(buffer)));
    });
  }

  /**
   * 蓝牙断开
   */
  async disconect() {
    if (this.device_state === 'off') {
      return;
    }
    if (this.infoOld !== '') {
      this.ble.disconnect(this.infoOld).then((res) => {
        this.device_state = 'off';
        this.scan(1);
        // this.dialog.showAlert('断开连接', JSON.stringify(this.info));
      });
    } else {
      this.ble.disconnect(this.info).then((res) => {
        this.device_state = 'off';
        this.scan(1);
        // this.dialog.showAlert('断开连接', JSON.stringify(this.info));
      });
    }
  }

  /**
   * 蓝牙状态监听
   */
  state() {
    this.ble.startStateNotifications().subscribe(state => {
      // this.dialog.showAlert('蓝牙状态监听', state);
      // this.device_state = state;
      if (state == 'off') {
        this.dialog.showAlert('提示', '蓝牙已关闭');
      }
    });
  }

  /**
   * 蓝牙停止状态监听
   */
  stopstate() {
    this.ble.stopStateNotifications().then(state => {
    });
  }


  /**
   * 校验和计算函数
   * @param data 
   * @param size 
   */
  checksum(data, size): any {

    let buffer = new Uint8Array(18);
    let j = 0;
    for (let i = 0; i < data.length - 1; i++) {
      buffer[i] = (parseInt(data[j] + data[j + 1], 16) & 0xff);
      j = j + 2;
    }
    let Cksum = 0;
    let num = 0;
    while (size > 1) {
      Cksum = ((Cksum + buffer[num]) & 0xffffffff);
      size = ((size - 1) & 0xffff);
      num++;
    }
    if (size) {
      Cksum = ((Cksum + buffer[17]) & 0xffffffff);
    }

    while (((Cksum >> 16) & 0xffff)) {
      Cksum = ((Cksum >> 16) & 0xffff) + (Cksum & 0xffff);
    }

    return (65535 - Cksum).toString(16);
  }

}
